<script setup lang="ts">
import { ref,onMounted,defineEmits } from 'vue'
import {Role} from './scripts/role.js'
import { Loop } from './scripts/system/Loop.js'
import { Resizer } from './scripts/system/Resizer.js'
import { 
  WebGLRenderer,
  NeutralToneMapping,
  ACESFilmicToneMapping,
  // PMREMGenerator,
  Euler,
  OrthographicCamera,
  Scene,
  DirectionalLight,
  SpotLight,
  SpotLightHelper,
  SRGBColorSpace,
  PCFSoftShadowMap,
  Vector3,
  EquirectangularReflectionMapping,
  AmbientLight ,
  Box3
} from 'three'
// import {RoomEnvironment} from 'three/examples/jsm/environments/RoomEnvironment.js'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
import {getCurrentInstance} from "vue";
import {mittTypes} from "@/util/types"
import {getAssetsFile} from "@/util/common.js";
import {getMinioTtsAudioFile} from "@/api/apiRequst"
import {useSceneStore} from '@/stores/scene';
// import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
// import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
// import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js';
// import { LUTPass } from 'three/examples/jsm/postprocessing/LUTPass.js';
// import { LUTCubeLoader } from 'three/examples/jsm/loaders/LUTCubeLoader.js';
// import { LUT3dlLoader } from 'three/examples/jsm/loaders/LUT3dlLoader.js';
// import { LUTImageLoader } from 'three/examples/jsm/loaders/LUTImageLoader.js';
// import { WebGLPathTracer, BlurredEnvMapGenerator, GradientEquirectTexture } from 'three-gpu-pathtracer';

const { appContext : { config: { globalProperties } } } = getCurrentInstance();

const internalInstance = getCurrentInstance()
const emitter = internalInstance.appContext.config.globalProperties.emitter
const sceneStore = useSceneStore()
const props = defineProps({
  scale:{
    type: Number,
    default: 1
  },
  url: String,
  fullBody: Boolean,
  actionList: {
    type: Array,
    default: []
  },
  x: {
    type: Number,
    default: '0'
  },
  y: {
    type: Number,
    default: '0'
  },
  width: {
    type: Number,
    default: '200'
  },
  height: {
    type: Number,
    default: '500'
  },
})
const emit = defineEmits(['remove'])

let renderDom: any = ref<InstanceType<any>>()


let scene = null;
let glRenderer = null;
let pmremGenerator = null;
let camera = null;
let loop = null;
let resizer = null;
let composer = null;
let lutPass = null;
let pathTracer, floor, gradientMap;
const pathTracerMinSamples = 3;
	const pathTracerMaxSamples = 65536;
	const samplesNumber = 16;
  const maxSamples = Math.max( pathTracerMinSamples, Math.min( pathTracerMaxSamples, samplesNumber ) );
const rotX = ref(9)
const rotY = ref(8)
const rotZ = ref(19)
const params = ref([
'Bourbon 64.CUBE',
				'Chemical 168.CUBE',
				'Clayton 33.CUBE',
				'Cubicle 99.CUBE',
				'Remy 24.CUBE',
				'Presetpro-Cinematic.3dl',
				'NeutralLUT',
				'B&WLUT',
				'NightLUT',
        'none'
])
const lutSelect = ref('Bourbon 64.CUBE')
function setEnvRot(){
  scene.environmentRotation = new Euler(rotX.value/100*360,rotY.value/100*360,rotZ.value/100*360)
}
function init(){

  scene = new Scene()

  // let directionalLight = new DirectionalLight('white', 3)
  // directionalLight.position.set(0, 2, 1)
  // // let ambientLight = new AmbientLight(0xffffff,10)
  // // directionalLight.target = playerRole.model
  // // directionalLight.lookAt(playerRole.model)
  // scene.add(directionalLight)
  // scene.add(ambientLight)
  let spotLight = new SpotLight( 0xffffff, 2 );
  spotLight.position.set( 0, 2.5, 1 );
  spotLight.angle = Math.PI / 6;
  spotLight.penumbra = 1;
  spotLight.decay = 2;
  spotLight.distance = 0;
  spotLight.lookAt(new Vector3(0,0,0))

  spotLight.castShadow = true;
  spotLight.shadow.mapSize.width = 1024;
  spotLight.shadow.mapSize.height = 1024;
  spotLight.shadow.camera.near = 1;
  spotLight.shadow.camera.far = 10;
  spotLight.shadow.focus = 1;
  scene.add( spotLight );



  glRenderer = new WebGLRenderer({
    antialias: true, //开启锯齿
    alpha: true
  })
  glRenderer.shadowMap.type = PCFSoftShadowMap
  glRenderer.shadowMap.enabled = true
  glRenderer.setPixelRatio( 1.5 );
  glRenderer.toneMapping = NeutralToneMapping
  glRenderer.gammaOutput  =true;
  glRenderer.toneMappingExposure =1;
  glRenderer.localClippingEnabled = true;
  glRenderer.physicallyCorrectLights = true;
  glRenderer.outputColorSpace = SRGBColorSpace;
  
  // modelview光源
  // pmremGenerator = new PMREMGenerator( glRenderer );
	// pmremGenerator.compileEquirectangularShader();
  // scene.environment = pmremGenerator.fromScene( new RoomEnvironment(), 0.04 ).texture;


  // 正投影相机
  const k = renderDom.value.clientWidth / renderDom.value.clientHeight; //canvas画布宽高比
  const s = 2//控制left, right, top, bottom范围大小
  camera = new OrthographicCamera(-s * k, s * k, s, -s, 1, 100);
  camera.position.set(0, 1.32, 3)

  // initialize the pathtracer
  // pathTracer = new WebGLPathTracer( glRenderer );
  // pathTracer.filterGlossyFactor = 0.5;
  // pathTracer.minSamples = 3;
  // pathTracer.renderScale = 1;
  // pathTracer.setScene( scene, camera );
  // pathTracer.updateCamera();
  // pathTracer.enablePathTracing = true;
	// pathTracer.tiles.set( 6, 6 );

  let url = "https://aiimg.huilan.com/";
  let hdrurl ='innerPages/commonAssets/texture/equirectangular/studio_small_09_1k.hdr';
  new RGBELoader()
  .setPath(url)
  .load(
    hdrurl,
    function (texture) {
      texture.colorSpace = SRGBColorSpace
      texture.mapping = EquirectangularReflectionMapping
      
      // scene.background = texture
      scene.environment = texture
      scene.environmentRotation = new Euler(rotX.value/100*360,rotY.value/100*360,rotZ.value/100*360)
      // glRenderer.render(scene, camera)
      // pathTracer.updateEnvironment();
      // pathTracer.updateMaterials();
    },
    function () {},
    function (error) {
      console.log(error)
    }
  )

  // 创建全局循环
  loop = new Loop(camera, scene, glRenderer)

  loop.start()
  //创建尺寸适配
  resizer = new Resizer(
    renderDom.value,
    camera as OrthographicCamera,
    glRenderer
  )
}

var playerRole;
var roleinfo = {
      "enable": true,
      "camRotation": [
          -1.5168211234570872,
          1.3952955544844565,
          1.5159807611098084
      ],
      "rotation": [
          0,
          0,
          0
      ],
      "camFov": 80,
      "scale": [
          1,
          1,
          1
      ],
      "position": [
          0,
          0,
          0
      ],
      "camPosition": [
          0,
          0,
          0
      ],
      "url": "",
      "actionList": "",
      "eulerAngle": [
          0,
          0,
          0
      ],
      "target": [
          0,
          0,
          0
      ]
}
const addNpcRole = async function (url:any,actionList:any,fullBody:any = false) {


  roleinfo.url = url
  roleinfo.actionList = actionList

  playerRole = await new Role(
      roleinfo,
      scene,
      camera,
      loop,
      emitter
  )
  await playerRole.init()


  playerRole.isNpc = true;

  // 滤镜
  // const lutMap = {
	// 			'Bourbon 64.CUBE': null,
	// 			'Chemical 168.CUBE': null,
	// 			'Clayton 33.CUBE': null,
	// 			'Cubicle 99.CUBE': null,
	// 			'Remy 24.CUBE': null,
	// 			'Presetpro-Cinematic.3dl': null,
	// 			'NeutralLUT': null,
	// 			'B&WLUT': null,
	// 			'NightLUT': null
	// 		};
  //     Object.keys( lutMap ).forEach( name => {

  //     if ( /\.CUBE$/i.test( name ) ) {
      
  //       new LUTCubeLoader()
  //         .load( 'luts/' + name, function ( result ) {
          
  //           lutMap[ name ] = result;
          
  //         } );
        
  //     } else if ( /\LUT$/i.test( name ) ) {
      
  //       new LUTImageLoader()
  //         .load( `luts/${name}.png`, function ( result ) {
          
  //           lutMap[ name ] = result;
          
  //         } );
        
  //     } else {
      
  //       new LUT3dlLoader()
  //         .load( 'luts/' + name, function ( result ) {
          
  //           lutMap[ name ] = result;
          
  //         } );
        
  //     }

  //     } );
  //     composer = new EffectComposer( glRenderer );
  //     composer.setPixelRatio( window.devicePixelRatio );
  //     composer.setSize( window.innerWidth, window.innerHeight );
  //     composer.addPass( new RenderPass( scene, camera ) );
  //     composer.addPass( new OutputPass() );

  //     lutPass = new LUTPass();
  //     composer.addPass( lutPass );
  
      

  glRenderer.setSize(renderDom.value.clientWidth, renderDom.value.clientHeight)
  glRenderer.setPixelRatio(1.5)
  glRenderer.setClearAlpha(0)
  renderDom.value.appendChild(glRenderer.domElement)
  playerRole.chatRenderer = glRenderer;
  setTimeout(() => {
    setFullBody(fullBody)
  }, 100);
  visibilitychange();
  let extraCamera = loop.addCameraView({
    left: 0,
    top: '0',
    width: 1,
    height: 1,
    opacity: '0',
    camera: camera,
    renderer: glRenderer,
    // renderTarget:new THREE.WebGLRenderTarget(),
    onUpdateCamera: function (camera, scene, renderer) {
      // 滤镜
      // if ( lutMap[ lutSelect.value ] ) {

      //   const lut = lutMap[ lutSelect.value ];
      //   lutPass.lut = lut.texture3D;
      //   composer.render();
      // }else{

      // }

      // 路径追踪
      // const samples = Math.floor( pathTracer.samples ) + 1;
      // pathTracer.renderSample();
      // if ( samples < maxSamples ) {
        
      //   // pathTracer.updateCamera();
      //   // pathTracer.pausePathTracing = false;
      // }

      
      

    }
  })
}
function setFullBody(val){
  let box = new Box3()
  box.setFromObject(playerRole.model,true)
  //包围盒计算的都是世界的
  box.min=playerRole.model.worldToLocal(box.min);
  box.max=playerRole.model.worldToLocal(box.max);
  let centor = box.getCenter(new Vector3(0, 0, 0))

  if(val){
    camera.position.set(0, centor.y, 3)
    resizer.setFrustumSize(box.max.y+0.09)
    resizer.onResize()
  }else{
    camera.position.set(0, 1.32, 3)
    resizer.setFrustumSize(box.max.y*0.75)
    resizer.onResize()
  }

}
/** 浏览器窗口监听（当点击审核跳转其他系统后，数据被审批完了，再次从浏览器窗口切换，请求接口） */
const visibilitychange = () => {
document.addEventListener('visibilitychange', function() {
  if (document.visibilityState === 'hidden') {
  } else {
    setTimeout(() => {
      setFullBody(props.fullBody) // 查询方法 - 方法中写调用接口代码
    }, 100);
    
    }
  });
}
let curViseme = [];
let curAudio = [];
let curSegment_id = null;
onMounted(() => {
  init()
  
  addNpcRole(props.url,props.actionList,props.fullBody)
  // emitter.on(mittTypes.LIVEKIT.MESSAGE_CHAT_RECIVE,function(data:any){
  //   let messageData = data.messageData;
  //   let from = data.from;
  //   if(from == mittTypes.LIVEKIT.MESSAGE_CHAT_FROM_TYPE.BOT){
  //     // let message = JSON.parse(messageData.message)
  //     curViseme = [];
  //     playerRole.clearSpeakData()
  //     playerRole.stopSpeak()
      
  //     console.log('收到新文字停止之前的表情序列')
      
  //   }
    
  // })

  emitter.on(mittTypes.WEBHUMAN.STOP_VISEME_AUDIO,async function(data:any){
    curViseme = [];
      curAudio = [];
      playerRole.clearSpeakData()
      playerRole.stopSpeak()
      
      console.log('收到停止回答按钮消息，停止回答表情和语音')
  })
  emitter.on(mittTypes.LIVEKIT.MESSAGE_VISEME_RECIVE,async function(data:any){
    
    

    let messageData = data.messageData;
    let from = data.from;
    let message = messageData
    if(!curSegment_id){
      curSegment_id = message.segment_id;
    }
    if(from == mittTypes.LIVEKIT.MESSAGE_CHAT_FROM_TYPE.BOT&&curSegment_id!=message.segment_id){
      curSegment_id = message.segment_id;
      curViseme = [];
      curAudio = [];
      playerRole.clearSpeakData()
      playerRole.stopSpeak()
      
      console.log('收到新文字停止之前的表情序列')
      
    }
    if(from == mittTypes.LIVEKIT.MESSAGE_CHAT_FROM_TYPE.BOT){
      
      // let audioFile = await getMinioTtsAudioFile({
      //   object_name:message.data.audio.object_name,
      // })
      // const blob = new Blob([audioFile], { type: 'audio/wav' });
      // const localUrl = (window.URL || webkitURL).createObjectURL(blob);
      // const audio = document.createElement('audio');
      // audio.style.display = 'none'; // 防止影响页面布局
      // audio.controls = true;
      // document.body.appendChild(audio);
      // audio.src = localUrl;
      // audio.playbackRate = 1; // 语速
      // audio.play();

      // 语音播放完毕后，需要手动释放内存
      // audio.onended = function () {
      //   document.body.removeChild(audio);
      //   URL.revokeObjectURL(localUrl);
      // };
      // console.log(audioFile)
      console.log(message.data.viseme)
      curViseme.push(message.data.viseme)
      // curAudio.push(audio)
      playerRole.setSpeakData(curViseme,messageData)
      playerRole.startSpeakByData()
      
      console.log('设置表情序列')
      
    }
    
  })
  emitter.on(mittTypes.LIVEKIT.MESSAGE_ACTION_RECIVE,function(data:any){
    playerRole.activeExtraAction(data)
    
  })
  emitter.on(mittTypes.WEBHUMAN.ACTION_PLAY,function(name:any){
    playerRole.activeExtraAction(name)
    
  })
  emitter.on(mittTypes.WEBHUMAN.ACTION_SET_BY_TIME,function(data:any){
    playerRole.setExtraActionByTime(data.actionName,data.time)
    
  })
  emitter.on(mittTypes.WEBHUMAN.VISEME_PLAY,function(data:any){
    
    playerRole.setSpeakData(data.viseme)
    playerRole.startSpeakByData()
    
  })
  emitter.on(mittTypes.WEBHUMAN.VISEME_STOP,function(name:any){
    curViseme = [];
    playerRole.clearSpeakData()
    playerRole.stopSpeak()
  })
  emitter.on(mittTypes.WEBHUMAN.CHANGE_COSTUME,function(url:any){
    roleinfo.url = url
    playerRole.setRoleInfo(roleinfo)
    playerRole.loadGl()
  })
  emitter.on(mittTypes.WEBHUMAN.ACTIVE_BASE_ACTION,function(data){
    playerRole.activateBaseActionByName(data.name,data.loopType,data.callback,data.noCross)
  })
  emitter.on(mittTypes.WEBHUMAN.STOP_BASE_ACTION,function(name:any){
    playerRole.stopBaseAction(name)
  })
  emitter.on(mittTypes.LIVEKIT.PATICIPANT_SPEAKING,function(paticipant:any){
    playerRole.voiceSpeaking = paticipant.isSpeaking
  })
})
</script>

<script lang="ts">
export default {
  name: 'AiHumanWebRenderer'
}
</script>
<template>
  <!-- hdr环境光旋转 -->
  <!-- <el-slider @input="setEnvRot" v-model="rotX" />
  <el-slider @input="setEnvRot" v-model="rotY" />
  <el-slider @input="setEnvRot" v-model="rotZ" /> -->
  <!-- 滤镜 -->
  <!-- <el-select
      v-model="lutSelect"
      placeholder="Select"
      size="large"
      style="width: 240px"
    >
      <el-option
        v-for="item in params"
        :key="item"
        :label="item"
        :value="item"
      />
    </el-select> -->
  <!-- <div id="bottomShadow":style="'display:none;transform:scaleX('+scaleX+');left:'+(parseFloat(props.x)+40)+'px;top:'+props.y+'px;width:'+props.width+'px;height:'+props.height+'px'" class="center">
      <img class="center" :style="'width:'+parseFloat(props.width)*0.5+'px;opacity:0.5;bottom:-20px;top:auto'" 
      :src="getAssetsFile('bottom.png')"
      >
      
  </div> -->
  <div :style="'transform:translate('+props.x+'px,'+props.y+'px);width:'+props.width+'px;height:'+props.height+'px'" class="renderDom" >
    <div :style="'transform:scale('+scale+');width:'+props.width+'px;height:'+props.height+'px;transform-origin:bottom center'" ref="renderDom"></div>
    <div v-show="sceneStore.projectConfig&&sceneStore.projectConfig.projectSet.platform!='guide'" id="loading" class="center" style="z-index: 9998;background-color: #ffffff00;">
      <img class="center" id="loadingBackImg" style="width: 100%" src="" />
      <div class="loader center">
        <img class="center" style="width: 80%;" 
        :src="getAssetsFile('aihuman.png')"
        >
      </div>
      <div id="progress-loader" class="progress-loader">
        <div id="loadProgress" class="progress"></div>
      </div>
    </div>
    
  </div>

</template>

<style scoped>
.center{
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  text-align: center;
}
.renderDom {
  position:absolute;
  bottom:0;
  top:0px;
  left:0px;
  right:0;
  margin:auto;
  width:200px;
  height: 500px;
}
.progress-loader {
  top: auto;
  left: 0;
  right: 0;
  bottom: 30px;
  margin: auto;
  position: absolute;
  /* transform: translate(-50%, -50%); */
  width: 80%;
  background: rgb(32 41 58);
  height: 10px;
  border-radius: 7px;
}

.progress {
  width: 1px;
  height: 10px;
  border-radius: 7px;
  background: rgb(63 102 249);
  transition: 0.5s;
  /* animation: loading_44 5s cubic-bezier(.4,1.01,1,1) infinite; */
}
</style>